---
title: Package Examples
description: A set of `.pkg.lua` examples for creating Zoi packages.
---

This document provides a set of examples for creating `.pkg.lua` files. These files are the core of Zoi's packaging system, defining everything from metadata to installation methods using the power of Lua scripting.

## Comprehensive Package Example

This is a comprehensive example that showcases many of Zoi's packaging features. It defines a package with multiple, selectable installation methods, including pre-compiled binaries, compressed archives, an installer script, and building from source, with platform-specific logic.

```lua
-- hello.pkg.lua

-- Using local variables to follow DRY principle.
local repo_owner = "Zillowe"
local repo_name = "Hello"
local version = "2.0.0"
local git_url = "https://github.com/" .. repo_owner .. "/" .. repo_name .. ".git"
local release_base_url = "https://github.com/" .. repo_owner .. "/" .. repo_name .. "/releases/download/v" .. version

-- Platform mapping allows customizing OS and architecture names for URLs and filenames.
-- The key is the platform string reported by Zoi (e.g. "macos", "linux-amd64").
-- The value is the desired platform string to be used in the package script.
local platform_map = {
	macos = "darwin",
}

local function get_mapped_platform()
	local current_platform = SYSTEM.OS .. "-" .. SYSTEM.ARCH
	return platform_map[current_platform] or platform_map[SYSTEM.OS] or current_platform
end

local function get_mapped_os()
	return get_mapped_platform():match("([^%-]+)")
end

package({
	name = "hello",
	repo = "zillowe",
	version = version,
	description = "Hello World",
	website = "https://github.com/Zillowe/Hello",
	git = git_url,
	maintainer = {
		name = "Your Name",
		email = "your-email@example.com",
	},
	author = {
		name = "Zillowe Foundation",
		website = "https://zillowe.qzz.io",
		email = "contact@zillowe.qzz.io",
		key = "https://zillowe.pages.dev/keys/zillowe-main.asc",
		key_name = "zillowe-main",
	},
	license = "Apache-2.0",
	bins = { "hello" },
	conflicts = { "hello" },
})

install({
	selectable = true,
	{
		name = "Binary",
		type = "binary",
		url = (function()
			return release_base_url .. "/hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH
		end)(),
		platforms = { "all" },
		checksums = (function()
			return release_base_url .. "/checksums-512.txt"
		end)(),
		sigs = {
			{
				file = (function()
					return "hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH
				end)(),
				sig = (function()
					return release_base_url .. "/hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH .. ".sig"
				end)(),
			},
		},
	},
	{
		name = "Compressed Binary",
		type = "com_binary",
		url = (function()
			local ext
			if SYSTEM.OS == "windows" then
				ext = "zip"
			else
				ext = "tar.xz"
			end
			return release_base_url .. "/hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH .. "." .. ext
		end)(),
		platforms = { "all" },
		checksums = (function()
			return release_base_url .. "/checksums-512.txt"
		end)(),
		sigs = {
			{
				file = (function()
					local ext
					if SYSTEM.OS == "windows" then
						ext = "zip"
					else
						ext = "tar.xz"
					end
					return "hello-" .. get_mapped_os() .. "-" .. SYSTEM.ARCH .. "." .. ext
				end)(),
				sig = (function()
					local ext
					if SYSTEM.OS == "windows" then
						ext = "zip"
					else
						ext = "tar.xz"
					end
					return release_base_url
							.. "/hello-"
							.. get_mapped_os()
							.. "-"
							.. SYSTEM.ARCH
							.. "."
							.. ext
							.. ".sig"
				end)(),
			},
		},
	},
	{
		name = "Install Script",
		type = "script",
		url = (function()
			local ext
			if SYSTEM.OS == "windows" then
				ext = "ps1"
			else
				ext = "sh"
			end
			return "https://raw.githubusercontent.com/Zillowe/Hello/refs/heads/main/app/install." .. ext
		end)(),
		platforms = { "all" },
	},
	{
		name = "Build from source",
		type = "source",
		url = git_url,
		platforms = { "linux", "macos", "windows" },
		build_commands = {
			'go build -o hello -ldflags="-s -w" ./src',
		},
		bin_path = (function() -- the final binary path
			local bin
			if SYSTEM.OS == "windows" then
				bin = "hello.exe"
			else
				bin = "./hello"
			end
			return bin
		end)(),
		files = {
			{
				platforms = { "linux", "macos" },
				files = {
					{
						source = "README.md",
						destination = "/usr/local/share/doc/hello/README.md",
					},
				},
			},
			{
				platforms = { "windows" },
				files = {
					{
						source = "README.md",
						destination = "C:\\ProgramData\\hello\\README.md",
					},
				},
			},
		},
	},
})

dependencies({
	build = {
		required = { "native:go" },
	},
})
```

## Build from Source Package

For packages that need to be compiled on the user's machine, use the `source` installation type.

```lua
-- dev/compiler.pkg.lua
package({
  name = "compiler",
  repo = "community",
  version = "0.1.0",
  description = "A new programming language compiler.",
  git = "https://github.com/user/compiler",
  tags = { "compiler", "devtools" },
  maintainer = {
    name = "Your Name",
    email = "your.email@example.com"
  }
})

install({
  {
    type = "source",
    url = PKG.git, -- URL to the git repository.
    platforms = { "linux-amd64", "macos-amd64", "windows-amd64" },
    -- Optional: build inside a Docker container for reproducibility.
    docker_image = "hub:golang:1.21-alpine",
    -- Commands to execute in the cloned repository to build.
    build_commands = {
      "go build -o compiler"
    },
    -- Path to the built binary, relative to the repo root.
    -- When using docker_image, this is the path inside the container.
    bin_path = "./compiler"
  }
})

dependencies({
  build = {
    required = { "zoi:go", "native:make" },
    optional = { "cargo:some-build-tool:additional build helper" }
  },
  runtime = {
    required = { "native:openssl" }
  }
})
```

## Package Collection

A `collection` is a meta-package that only installs other packages as dependencies.

```lua
-- collections/web-dev-essentials.pkg.lua
package({
  name = "web-dev-essentials",
  repo = "community",
  type = "collection", -- Set the package type to 'collection'.
  version = "1.0",
  description = "A collection of essential tools for web development.",
  tags = { "collection", "web", "devtools" },
  maintainer = {
    name = "Community",
    email = "community@example.com"
  }
})

-- The 'runtime' dependencies are the packages that will be installed.
dependencies({
  runtime = {
    required = {
      "zoi:node",
      "zoi:bun",
      "native:git"
    },
    optional = {
      "npm:pnpm",
      "npm:serve",
      "npm:typescript"
    }
  }
})
```

## Service Package

A `service` package is for applications that need to run in the background. Zoi can manage starting and stopping them.

```lua
-- services/my-database.pkg.lua
package({
  name = "my-database",
  repo = "community",
  type = "service", -- Set the package type to 'service'.
  version = "5.7",
  description = "A lightweight database server.",
  tags = { "service", "database" },
  maintainer = {
    name = "Your Name",
    email = "your.email@example.com"
  },
  -- The 'service' block defines how to manage the service.
  service = {
    {
      platforms = { "linux-amd64", "macos-amd64" },
      start = { "my-database --config /etc/my-database.conf" },
      stop = { "pkill my-database" }
    }
  }
})

install({
  {
    type = "binary",
    url = "https://example.com/my-database-v" .. PKG.version .. "-" .. SYSTEM.OS .. "-" .. SYSTEM.ARCH,
    platforms = { "linux-amd64", "macos-amd64" }
  }
})
```

## Library Package

A `library` package installs shared/static libraries and header files. It can also generate a `.pc` file for `pkg-config`.

```lua
-- libs/my-library.pkg.lua
package({
  name = "my-library",
  repo = "community",
  type = "library",
  version = "1.2.0",
  description = "A library for doing awesome things.",
  tags = { "library", "c++" },
  maintainer = {
    name = "Your Name",
    email = "your.email@example.com"
  },
  -- This block is used to generate the .pc file
  pkg_config = {
    description = "My Awesome Library",
    libs = "-L/usr/local/lib -lmy-library",
    cflags = "-I/usr/local/include/my-library"
  }
})

install({
  {
    type = "com_binary",
    url = "https://example.com/my-library/v" .. PKG.version .. "-" .. SYSTEM.OS .. "-" .. SYSTEM.ARCH .. ".tar.gz",
    platforms = { "linux-amd64" }
  }
})
```

## Script Package

A `script` package runs a series of inline shell commands instead of installing a binary. This is useful for complex setup actions.

```lua
-- my-setup-script.pkg.lua
package({
  name = "my-setup-script",
  repo = "community",
  type = "script",
  version = "1.0",
  description = "A package that runs a series of setup commands.",
  tags = { "script", "setup" },
  maintainer = {
    name = "Your Name",
    email = "your.email@example.com"
  },
  -- The 'script' field contains the commands to run.
  script = {
    {
      platforms = { "linux", "macos" },
      install = {
        "echo 'Creating configuration directory...'",
        "mkdir -p ~/.config/my-app",
        "echo 'hello: world' > ~/.config/my-app/config.yml"
      },
      uninstall = {
        "echo 'Removing configuration...'",
        "rm -rf ~/.config/my-app"
      }
    }
  }
})
```

## App Template Package

An `app` package defines a template to scaffold applications via `zoi create <source> <appName>`. It is not installable directly.

```lua
-- apps/rails-app.pkg.lua
package({
  name = "rails-app",
  repo = "community",
  type = "app",
  version = "7",
  description = "Rails app template",
  tags = { "app", "rails", "ruby" },
  maintainer = {
    name = "Your Name",
    email = "you@example.com"
  },
  -- Platform-specific create command and optional follow-up commands
  app = {
    {
      platforms = { "all" },
      appCreate = "rails new ${appName}",
      commands = {
        "cd ${appName} && bundle install",
        "cd ${appName} && git init"
      }
    }
  }
})

dependencies({
  runtime = {
    required = { "zoi:@core/ruby", "zoi:@main/gems/rails" }
  }
})
```

## Extension Package

An `extension` package modifies Zoi's configuration. It is managed with `zoi extension add` and `zoi extension remove`.

```lua
-- extensions/corp-repos.pkg.lua
package({
  name = "corp-repos",
  repo = "community",
  type = "extension",
  version = "1.0",
  description = "Adds the official corporate package repositories for MyCorp.",
  tags = { "extension", "config" },
  maintainer = {
    name = "MyCorp IT",
    email = "it@mycorp.com"
  },
  extension = {
    type = "zoi",
    changes = {
      { type = "repo-git", add = "https://git.mycorp.com/zoi-packages.git" },
      { type = "repo-add", add = "test" },
      { type = "registry-repo", add = "https://zoi-mirror.mycorp.com/Zoidberg.git" }
    }
  }
})
```
